D			[0-9]
L			[a-zA-Z_]

%{
#include <stdio.h>
#include <string.h>
#include "fgc.h"
#include "fgc.tab.h"

    void count();
    void comment();
    int check_type();
    void unmatched_char();

    int column = 0;
    int row = 0;

    extern char path[];
    extern char file_input[];

#define MAX_INCLUDE_DEPTH 10
    YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
    char include_file_stack[MAX_INCLUDE_DEPTH][100];
    int include_row_stack[MAX_INCLUDE_DEPTH];
    int include_column_stack[MAX_INCLUDE_DEPTH];
    int include_stack_ptr = 0;

%}

%x incl

%%

#include          { count(); BEGIN(incl); }

<incl>[ \t]*      { count(); /* eat the whitespace */ }
<incl>[^\n]+   { /* got the include file name */
    count();
    char *p = yytext, *new_p;
    if ((new_p = strchr(p, '\"')) == NULL) {
        fprintf(stderr, "\"filename\" needed");
        exit(1);
    }
    new_p++;
    p = new_p;
    while (*new_p != '\"') {
        if (*new_p == 0) {
            fprintf(stderr, "\"filename\" needed");
            exit(1);
        }
        new_p++;
    }
    char buf[1000];
    memset(buf, 0x0, sizeof(buf));
    memcpy(buf, p, new_p-p);

    if (include_stack_ptr >= MAX_INCLUDE_DEPTH) {
        fprintf(stderr, "includes nested too deeply");
        exit(1);
    }
    strcpy(include_file_stack[include_stack_ptr], file_input);
    strcpy(file_input, buf);
    include_column_stack[include_stack_ptr] = column;
    include_row_stack[include_stack_ptr] = row;
    include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;

    include_stack_ptr++;

    yyin = fopen(buf, "r");
    if (!yyin) {
        char bufpath[1000];
        strcpy(bufpath, path);
        strcat(bufpath, "/");
        strcat(bufpath, buf);
        yyin = fopen(bufpath, "r");
        if (!yyin) {
            fprintf(stderr, "can't open file '%s'", buf);
            exit(1);
        }
    }
    yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
    BEGIN(INITIAL);
    column = 0;
    row = 0;
}

<<EOF>>           {
    if (--include_stack_ptr < 0) {
        yyterminate();
    }
    else {
        strcpy(file_input, include_file_stack[include_stack_ptr]);

        yy_delete_buffer(YY_CURRENT_BUFFER);
        yy_switch_to_buffer(include_stack[include_stack_ptr]);
        column = include_column_stack[include_stack_ptr];
        row = include_row_stack[include_stack_ptr];
    }
}    

"/*"			{ comment(); }
"//"[^\n]*		{ /* consume //-comment */ }


"break"			{ count(); return(BREAK); }
"continue"		{ count(); return(CONTINUE); }
"else"			{ count(); return(ELSE); }
"float"			{ count(); return(FLOAT); }
"for"			{ count(); return(FOR); }
"if"			{ count(); return(IF); }
"int"			{ count(); return(INT); }
"return"		{ count(); return(RETURN); }
"void"			{ count(); return(VOID); }
"while"			{ count(); return(WHILE); }
"system"                { count(); return(SYSTEM); }

{L}({L}|{D})*		{
    count();
    yylval.pid = new char[sizeof(char) * (strlen(yytext) + 1)];
    sprintf(yylval.pid, "%s", yytext);
    return(IDENTIFIER);
                    }

{D}+			{
    count();
    yylval.tconst.type = tINT;
    sscanf(yytext, "%d", &yylval.tconst.value.i);
    return(CONSTANT);
                }

{D}*"."{D}+		{
    count();
    yylval.tconst.type = tFLOAT;
    sscanf(yytext, "%f", &yylval.tconst.value.f);
    return(CONSTANT);
                }

\"(\\.|[^\\"\n])*\"	{ count(); return(STRING_LITERAL); }

">>="			{ count(); return(RIGHT_ASSIGN); }
"<<="			{ count(); return(LEFT_ASSIGN); }
"+="			{ count(); return(ADD_ASSIGN); }
"-="			{ count(); return(SUB_ASSIGN); }
"*="			{ count(); return(MUL_ASSIGN); }
"/="			{ count(); return(DIV_ASSIGN); }
"%="			{ count(); return(MOD_ASSIGN); }
"&="			{ count(); return(AND_ASSIGN); }
"^="			{ count(); return(XOR_ASSIGN); }
"|="			{ count(); return(OR_ASSIGN); }
">>"			{ count(); return(RIGHT_OP); }
"<<"			{ count(); return(LEFT_OP); }
"++"			{ count(); return(INC_OP); }
"--"			{ count(); return(DEC_OP); }
"&&"			{ count(); return(AND_OP); }
"||"			{ count(); return(OR_OP); }
"<="			{ count(); return(LE_OP); }
">="			{ count(); return(GE_OP); }
"=="			{ count(); return(EQ_OP); }
"!="			{ count(); return(NE_OP); }
";"			{ count(); return(';'); }
("{"|"<%")		{ count(); return('{'); }
("}"|"%>")		{ count(); return('}'); }
","			{ count(); return(','); }
":"			{ count(); return(':'); }
"="			{ count(); return('='); }
"("			{ count(); return('('); }
")"			{ count(); return(')'); }
("["|"<:")		{ count(); return('['); }
("]"|":>")		{ count(); return(']'); }
"&"			{ count(); return('&'); }
"!"			{ count(); return('!'); }
"~"			{ count(); return('~'); }
"-"			{ count(); return('-'); }
"+"			{ count(); return('+'); }
"*"			{ count(); return('*'); }
"/"			{ count(); return('/'); }
"%"			{ count(); return('%'); }
"<"			{ count(); return('<'); }
">"			{ count(); return('>'); }
"^"			{ count(); return('^'); }
"|"			{ count(); return('|'); }
"?"			{ count(); return('?'); }

[ \t\v\n\f]		{ count(); }
.			{ unmatched_char(); }

%%

int yywrap() {
	return 1;
}


void comment() {
	char c, prev = 0;
  
	while ((c = yyinput()) != EOF) {     /* (EOF maps to 0) */
		if (c == '/' && prev == '*')
			return;
		prev = c;
	}
	fprintf(stderr, "unterminated comment");
}

void count() {
    int i;
    for (i = 0; yytext[i] != '\0'; i++)
        if (yytext[i] == '\n') {
            row ++;
            column = 0;
        }
        else if (yytext[i] == '\t')
            column += 8 - (column % 8);
        else
            column++;

    //	ECHO;
}

void unmatched_char() {
    fprintf(stderr, "unmatched character <%s>", yytext);
}
